package club.janna.jrpc.util;

import club.janna.jrpc.cluster.ClusterInvoker;
import club.janna.jrpc.register.Register;
import club.janna.jrpc.rpc.RPCResponse;
import club.janna.jrpc.rpc.protocol.Protocol;
import lombok.Builder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;

@Slf4j
@Builder
public class JRPCBootstrap {

    /**
     * URI模板
     */
    private static final String URI_TEMPLATE = "%s://%s:%d/%s?" +
            "&transport=%s" +
            "&serialization=%s";

    /**
     * 注册中心地址
     */
    private String registry;

    /**
     * 使用的协议
     */
    private String protocol;

    /**
     * 监听的host
     */
    private String host;

    /**
     * 监听的port
     */
    private Integer port;

    /**
     * 使用的传输层
     */
    private String transport;

    /**
     * 使用的序列化方式
     */
    private String serialization;

    /**
     * 发布一个服务
     */
    public void publish(Object bean) {
        Class<?> serviceInterface = bean.getClass().getInterfaces()[0];
        if(!StringUtils.hasText(host)) {
            try {
                InetAddress inetAddress = InetAddress.getLocalHost();
                host = inetAddress.getHostAddress();
            } catch (UnknownHostException e) {
                log.warn("获取本机ip出错", e);
            }
            if(!StringUtils.hasText(host))
                host = "127.0.0.1";
        }
        if(port == null)
            port = 20880;
        if(!StringUtils.hasText(serialization))
            serialization = "java";
        if(!StringUtils.hasText(transport))
            transport = "netty";
        if(!StringUtils.hasText(protocol))
            protocol = "jrpc";
        if(!StringUtils.hasText(registry))
            registry = "redis://localhost:6379";

        String uri = String.format(URI_TEMPLATE, protocol, host, port, serviceInterface.getName(), transport, serialization);
        Protocol protocolService = SPIServiceProvider.getProtocol(this.protocol);
        URI serviceURI = null;
        try {
            serviceURI = new URI(uri);
            protocolService.publish(serviceInterface, serviceURI, invocation -> {
                RPCResponse<Object> rpcResponse = new RPCResponse<>();
                rpcResponse.setId(invocation.getId());
                if(serviceInterface != invocation.getTarget()) {
                    RuntimeException t = new RuntimeException("target not found!");
                    rpcResponse.setThrowable(t);
                    rpcResponse.setStatus(RPCResponse.Status.ERROR);
                    throw t;
                }
                try {
                    Method method = serviceInterface.getMethod(invocation.getMethod(), invocation.getParameterTypes());
                    Object result = method.invoke(bean, invocation.getArgs());
                    rpcResponse.setResult(result);
                    rpcResponse.setStatus(RPCResponse.Status.SUCCESS);
                } catch (Exception e) {
                    e.printStackTrace();
                    rpcResponse.setThrowable(e);
                    rpcResponse.setStatus(RPCResponse.Status.ERROR);
                }
                return rpcResponse;
            });
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }

        try {
            URI registryURI = new URI(registry);
            Register registerService = SPIServiceProvider.getRegister(registryURI);
            registerService.registerProvider(serviceInterface.getName(), serviceURI);
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }

        log.info("服务暴露完成，URI -> {}", uri);
    }

    /**
     * 引用一个服务
     * @param type
     * @return
     */
    public Object reference(Class<?> type, String loadBalancer) {
        return ProxyFactory.getProxyObject(new ClusterInvoker(registry, type.getName(), loadBalancer), type);
    }
}
